import java.awt.Color;
import java.awt.Graphics;

public class Ball extends GameObject {
	private Player p;
	private final static int r = 30;
	private int count = 0;
	
	/**
	 * 
	 * @param p Player
	 * @param xPos x position
	 * @param yPos y position
	 * @param vx velocity of x coordinate: + for go right, and - for go left
	 * @param vy velocity of y coordinate: + for go right, and - for go left
	 */
	public Ball(Player p, int xPos, int yPos, int vx, int vy) {
		
		super(xPos, yPos, r, r, vx, vy);
		
		this.setP(p);
	}
	
	public Ball() {
		super(100, 50, r, r, 0, 1);
	}
	
	public void checkCollision(Main m) {
		int X = m.getWidth();
		
		// Top
		if(yPos < (28 + Math.abs(vy))) {
			vy = Math.abs(vy);
			// increase the velocity of y direction
			if(count < 3) {
				count++;
			}
			else {
				if((vy < 0) && (vy > -5)) {
					vy--;
				}
				else if(vy < 5) {
					vy++;
				}
				
				//auto resize the panel
				if(p.getWidth() < 520) {
					p.setWidth(p.getWidth() + Math.abs(vy) * 10);
				}
				
				count = 0;
			}
		}
		
		// Left && Right
		if(xPos < (2 + Math.abs(vx))) {
			vx = Math.abs(vx);
		}
		else if(xPos > (X - r - 2 - Math.abs(vx))) {
			vx = -Math.abs(vx);
		}
		
		// Player
		if(rect.intersects(p.getRect())) {
			
			vy = -vy;
			
			if(Math.abs(vx) < 5) {
				if(p.isLeft()) {
					vx--;
				}
				else if(p.isRight()) {
					vx++;
				}
			}
		}
		
		// other Ball
		BallCollision(m);
	}
	
	public void BallCollision(Main m) {
		Ball b1 = this;
		for(Ball b2 : m.balls) {
			//two balls are same
			if(b1 == b2) {
				continue;
			}
			
			Vector2D vB1 = new Vector2D(b1.vx, b1.vy);
			Vector2D vB2 = new Vector2D(b2.vx, b2.vy);
			//Detect collision
			Vector2D dir = 
					new Vector2D(b2.xPos - b1.xPos - b1.vx,
							b2.yPos - b1.yPos - b1.vy);
			
			if((dir.lenght() < (r + 5)) && (dir.lenght() > (r - 5))) {
				//-- solve the collision
				// normalize the dir
				dir = dir.normalize();
				
				//perpendicular of dir
				Vector2D dirP = dir.perpendicular();
				
				// velocity of b1 on dirP vDirPb1 = vB1 * dirP . dirP^
				Vector2D vDirPb1 = new Vector2D();
				vDirPb1 = dirP.scalarMultiple(vB1.scalarMultiple(dirP));
				// velocity of b2 on dirP vDirb2 = vB2 * dirP . dirP^
				Vector2D vDirPb2 = new Vector2D();
				vDirPb2 = dirP.scalarMultiple(vB2.scalarMultiple(dirP));
				
				// velocity of b1 on dirP vDirb1 = vB1 * dir . dir^
				Vector2D vDirb1 = new Vector2D();
				vDirb1 = dir.scalarMultiple(vB1.scalarMultiple(dir));
				// velocity of b2 on dirP vDirb2 = vB2 * dir . dir^
				Vector2D vDirb2 = new Vector2D();
				vDirb2 = dir.scalarMultiple(vB2.scalarMultiple(dir));
				
				/**
				 * The component of velocity on dirP is conservative
				 * The component of velocity on dir is change
				 * this equals minus each other
				 * So the new velocity is:
				 */
				vB1 = vDirPb1.plus(vDirb2);
				vB2 = vDirPb2.plus(vDirb1);
				
				int vTmp[] = new int[2];
				
				vTmp = vB1.floorInt();
				
				this.vx = vTmp[0];
				this.vy = vTmp[1];
				
				vTmp = vB2.floorInt();
				
				b2.setVx(vTmp[0]);
				b2.setVy(vTmp[1]);
			}
		}
	}

	@Override
	public void update(Main screen) {
		if(yPos + r/2 > p.getyPos()) {
			screen.balls.remove(this);
			p.setHealth(p.getHealth() - 1);
		}
		
		// check the collision to Player and the collision to wall
		checkCollision(screen);
		
//		while(Math.abs(vx) > 5) {
//			vx = Math.abs(vx) / 5;
//		}
//		
//		while(Math.abs(vy) > 5) {
//			vy = Math.abs(vy) / 5;
//		}
		
		// new position
		xPos += vx;
		yPos += vy;
		
		//update for rectangle of ball
		rect.x = xPos;
		rect.y = yPos;
	}

	@Override
	public void render(Graphics g, Main screen) {
		update(screen);
		
		//draw ball
		g.setColor(new Color(255,125,75));
		g.fillOval(xPos, yPos, width, height);
	}

	public Player getP() {
		return p;
	}

	public void setP(Player p) {
		this.p = p;
	}

	public int getCount() {
		return count;
	}

	public void setCount(int count) {
		this.count = count;
	}

}
